package org.koin.hos.ext.koin;

import ohos.aafwk.ability.AbilityPackage;
import ohos.app.Context;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.Resource;
import org.koin.core.Koin;
import org.koin.core.KoinApplication;
import org.koin.core.definition.BeanDefinition;
import org.koin.core.definition.Definition;
import org.koin.core.error.DefinitionOverrideException;
import org.koin.core.logger.Level;
import org.koin.core.parameter.DefinitionParameters;
import org.koin.core.registry.PropertyRegistryExt;
import org.koin.core.scope.Scope;
import org.koin.dsl.DefinitionBinding;
import org.koin.dsl.Module;
import org.koin.dsl.ModuleDeclaration;
import org.koin.hos.logger.HosLogger;
import java.io.IOException;
import java.util.Arrays;
import java.util.Properties;

/**
 * Koin extensions for Hos
 */
public class KoinExt {

    /**
     * Setup Hos Logger for Koin
     *
     * @param level
     */
    public static KoinApplication HosLogger(KoinApplication app, Level level) {
        app.getKoin().setupLogger(new HosLogger(level));
        return app;
    }

    /**
     * Add Context instance to Koin container
     *
     * @param hosContext - Context
     */
    public static KoinApplication hosContext(KoinApplication app, Context hosContext) {
        Koin koin = app.getKoin();
        if (koin.getLogger().isAt(Level.INFO)) {
            koin.getLogger().info("[init] declare Hos Context");
        }

        if (hosContext instanceof AbilityPackage) {
            org.koin.core.module.Module module = Module.module(new ModuleDeclaration() {
                @Override
                public void invoke(org.koin.core.module.Module module) {
                    try {
                        BeanDefinition<Context> bean = module.single(Context.class,
                                new Definition<Context>() {
                            @Override
                            public Context invoke(Scope scope, DefinitionParameters parameters) {
                                return hosContext;
                            }
                        });

                        DefinitionBinding.bind(bean, AbilityPackage.class);

                    } catch (DefinitionOverrideException e) {
                        e.printStackTrace();
                    }
                }
            });
            try {
                koin.loadModules(Arrays.asList(module));
            } catch (DefinitionOverrideException e) {
                e.printStackTrace();
            }
        } else {
            org.koin.core.module.Module module = Module.module(new ModuleDeclaration() {
                @Override
                public void invoke(org.koin.core.module.Module module) {
                    try {
                        module.single(Context.class, new Definition<Context>() {
                            @Override
                            public Context invoke(Scope scope, DefinitionParameters parameters) {
                                return hosContext;
                            }
                        });

                    } catch (DefinitionOverrideException e) {
                        e.printStackTrace();
                    }
                }
            });
            try {
                koin.loadModules(Arrays.asList(module));
            } catch (DefinitionOverrideException e) {
                e.printStackTrace();
            }
        }

        return app;
    }

    /**
     * Load properties file from Assets
     *
     * @param app
     * @param koinPropertyFile
     */
    public static KoinApplication hosFileProperties(KoinApplication app,
                                                        String koinPropertyFile) {

        Koin koin = app.getKoin();
        Properties koinProperties = new Properties();
        try {
            Context hosContext = koin.get(Context.class);
            RawFileEntry rawFileEntry = hosContext.getResourceManager()
                    .getRawFileEntry(koinPropertyFile);

            if (rawFileEntry != null) {
                try {
                    Resource resource = rawFileEntry.openRawFile();
                    koinProperties.load(resource);
                    PropertyRegistryExt.saveProperties(koin.getPropertyRegistry(), koinProperties);

                    if (koin.getLogger().isAt(Level.INFO)) {
                        koin.getLogger().info("[Hos-Properties] loaded "
                                + koin.getPropertyRegistry().toString()
                                + " properties from assets/$koinPropertyFile");
                    }

                } catch (IOException e) {
                    koin.getLogger()
                            .error("[Hos-Properties] error for binding properties : "
                                    + e.getMessage());
                    e.printStackTrace();
                }
            } else {
                if (koin.getLogger().isAt(Level.INFO)) {
                    koin.getLogger().info("[Hos-Properties] no "
                            + koinPropertyFile
                            + " file to load");
                }
            }

        } catch (Exception e) {
            koin.getLogger()
                    .error("[Hos-Properties] error while loading properties from "
                            + koinPropertyFile
                            + " : "
                            + e.getMessage());
            e.printStackTrace();
        }

        return app;
    }

    public static KoinApplication hosFileProperties(KoinApplication app) {
        return hosFileProperties(app, "resources/rawfile/koin.properties");
    }
}
